package org.fast.develop.logicflow.runtime.convert.execute;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import org.fast.develop.logicflow.builder.AbstractLogicFlowNodeBuilder;
import org.fast.develop.logicflow.builder.LogicFlowBuilder;
import org.fast.develop.logicflow.core.meta.shape.LogicFlowDefinition;
import org.fast.develop.logicflow.runtime.LogicFlow;
import org.fast.develop.logicflow.runtime.convert.builder.DesignerModelBuilder;
import org.fast.develop.logicflow.runtime.convert.designer.model.DesignerEdgeModel;
import org.fast.develop.logicflow.runtime.convert.designer.model.DesignerJsonSchemaModel;
import org.fast.develop.logicflow.runtime.convert.designer.model.DesignerNodeModel;
import org.fast.develop.logicflow.runtime.exception.LogicFlowException;

import java.util.*;

/**
 * @author czh
 * @version V1.0
 * @data Created on 2022-12-31 12:30
 */
public class DesignerToDefinitionsExecutor {

    private DesignerBuilderFactory designerBuilderFactory;

    public DesignerToDefinitionsExecutor(DesignerBuilderFactory designerBuilderFactory) {
        this.designerBuilderFactory = designerBuilderFactory;
    }

    /**
     * 将设计器生成json转化为LogicFlowDefinition
     *
     * @param designerJson
     * @return
     */
    public LogicFlowDefinition execute(String designerJson) {

        DesignerJsonSchemaModel designerJsonSchemaModel = JSONUtil.toBean(designerJson, DesignerJsonSchemaModel.class);
        Map<String, DesignerNodeModel> nodeModelMap = new HashMap<>();
        Map<String, DesignerEdgeModel> edgeModelMap = new HashMap<>();
        Map<String, List<String>> relationMap = new HashMap<>();
        Map<String, List<String>> nodeOutgoingMap = new HashMap<>();
        designerJsonSchemaModel.getNodes().forEach(item -> {
            nodeModelMap.put(item.getId(), item);
        });
        designerJsonSchemaModel.getEdges().forEach(item -> {
            edgeModelMap.put(item.getId(), item);
            List<String> nextNodeIds;
            if (relationMap.containsKey(item.getSourceNodeId())) {
                nextNodeIds = relationMap.get(item.getSourceNodeId());
            } else {
                nextNodeIds = new ArrayList<>();
            }
            nextNodeIds.add(item.getTargetNodeId());
            relationMap.put(item.getSourceNodeId(), nextNodeIds);

            List<String> nodeOutgoings;
            if (nodeOutgoingMap.containsKey(item.getSourceNodeId())) {
                nodeOutgoings = nodeOutgoingMap.get(item.getSourceNodeId());
            } else {
                nodeOutgoings = new ArrayList<>();
            }
            nodeOutgoings.add(item.getId());
            nodeOutgoingMap.put(item.getSourceNodeId(), nodeOutgoings);
        });
        LogicFlowBuilder logicFlowBuilder = LogicFlow.createExecutableProcess(designerJsonSchemaModel.getId());

        DesignerNodeModel startNode = getStartNodel(designerJsonSchemaModel.getNodes());

        AbstractLogicFlowNodeBuilder abstractLogicFlowNodeBuilder = this.metaBuild(logicFlowBuilder, startNode);

        DesignerNodeModel nextNode = this.getNextNode(nodeModelMap, relationMap, startNode);
        while (Objects.nonNull(nextNode)) {
            if ("ifelse".equals(nextNode.getType())) {
                abstractLogicFlowNodeBuilder = this.elseIfMetaBuild(abstractLogicFlowNodeBuilder, nextNode, nodeModelMap, edgeModelMap, relationMap, nodeOutgoingMap, designerJsonSchemaModel);
//                nextNode = getEndNodel(designerJsonSchemaModel.getNodes());
                nextNode = null;
            } else {
                abstractLogicFlowNodeBuilder = this.metaBuild(abstractLogicFlowNodeBuilder, nextNode);
                nextNode = this.getNextNode(nodeModelMap, relationMap, nextNode);
            }
        }

        return logicFlowBuilder.done();
    }

    /**
     * 获取开始节点
     *
     * @param designerNodeModels
     * @return
     */
    private DesignerNodeModel getStartNodel(List<DesignerNodeModel> designerNodeModels) {
        DesignerNodeModel start = null;
        for (DesignerNodeModel designerNodeModel : designerNodeModels) {
            if ("start".equals(designerNodeModel.getType())) {
                start = designerNodeModel;
                break;
            }
        }
        if (Objects.nonNull(start)) {
            return start;
        } else {
            throw new LogicFlowException("获取开始节点失败");
        }
    }

    private DesignerNodeModel getEndNodel(List<DesignerNodeModel> designerNodeModels) {
        DesignerNodeModel start = null;
        for (DesignerNodeModel designerNodeModel : designerNodeModels) {
            if ("end".equals(designerNodeModel.getType())) {
                start = designerNodeModel;
                break;
            }
        }
        if (Objects.nonNull(start)) {
            return start;
        } else {
            throw new LogicFlowException("获取开始节点失败");
        }
    }

    /**
     * 单节点构建
     *
     * @param abstractLogicFlowNodeBuilder
     * @param designerNodeModel
     */
    private AbstractLogicFlowNodeBuilder metaBuild(AbstractLogicFlowNodeBuilder abstractLogicFlowNodeBuilder, DesignerNodeModel designerNodeModel) {
        DesignerModelBuilder designerModelBuilder = designerBuilderFactory.create(designerNodeModel.getType());
        designerModelBuilder.setDesignerModel(designerNodeModel);
        designerModelBuilder.setLogicFlowBuilder(abstractLogicFlowNodeBuilder);
        return designerModelBuilder.convert();
    }

    /**
     * elseIf节点构建
     *
     * @param abstractLogicFlowNodeBuilder
     * @param designerNodeModel
     */
    private AbstractLogicFlowNodeBuilder elseIfMetaBuild(
            AbstractLogicFlowNodeBuilder abstractLogicFlowNodeBuilder,
            DesignerNodeModel designerNodeModel,
            Map<String, DesignerNodeModel> nodeModelMap,
            Map<String, DesignerEdgeModel> edgeModelMap,
            Map<String, List<String>> relationMap,
            Map<String, List<String>> nodeOutgoingMap,
            DesignerJsonSchemaModel designerJsonSchemaModel
    ) {
        DesignerModelBuilder designerModelBuilder = designerBuilderFactory.create(designerNodeModel.getType());
        designerModelBuilder.setDesignerModel(designerNodeModel);
        designerModelBuilder.setLogicFlowBuilder(abstractLogicFlowNodeBuilder);
        abstractLogicFlowNodeBuilder = designerModelBuilder.convert();
        List<String> nodeOutgoingIds = nodeOutgoingMap.get(designerNodeModel.getId());
        if (Objects.isNull(nodeOutgoingIds)) {
            throw new LogicFlowException(StrUtil.format("解析错误，条件网关id = {} 获取信息失败", designerNodeModel.getId()));
        }
        for (String lineId : nodeOutgoingIds) {
            DesignerEdgeModel designerEdgeModel = edgeModelMap.get(lineId);
            String condition = null;
            String name = "条件";
            Boolean isDefault = false;
            if (Objects.nonNull(designerEdgeModel.getProperties()) && designerEdgeModel.getProperties().containsKey("condition")) {
                condition = (String) designerEdgeModel.getProperties().get("condition");
            }
            if (Objects.nonNull(designerEdgeModel.getProperties()) && designerEdgeModel.getProperties().containsKey("isDefault")) {
                isDefault = (Boolean) designerEdgeModel.getProperties().get("isDefault");
            }
            if (Objects.nonNull(designerEdgeModel.getText()) && designerEdgeModel.getText().containsKey("value")) {
                name = (String) designerEdgeModel.getText().get("value");
            }
            if (isDefault) {
                abstractLogicFlowNodeBuilder.condition(name);
            } else {
                abstractLogicFlowNodeBuilder.condition(name, condition);
            }
            if (Objects.isNull(designerEdgeModel)) {
                throw new LogicFlowException(StrUtil.format("解析错误，连线id = {} 获取信息失败", lineId));
            }
            DesignerNodeModel nextNode = nodeModelMap.get(designerEdgeModel.getTargetNodeId());
            if (Objects.isNull(nextNode)) {
                throw new LogicFlowException(StrUtil.format("解析错误，节点id = {} 获取信息失败", nextNode.getId()));
            }
            while (Objects.nonNull(nextNode)) {
                if ("ifelse".equals(nextNode.getType())) {
                    abstractLogicFlowNodeBuilder = this.elseIfMetaBuild(abstractLogicFlowNodeBuilder, nextNode, nodeModelMap, edgeModelMap, relationMap, nodeOutgoingMap, designerJsonSchemaModel);
                    nextNode = getEndNodel(designerJsonSchemaModel.getNodes());
                } /*else if ("end".equals(nextNode.getType())) {
                    break;
                }*/ else {
                    abstractLogicFlowNodeBuilder = this.metaBuild(abstractLogicFlowNodeBuilder, nextNode);
                    nextNode = this.getNextNode(nodeModelMap, relationMap, nextNode);
                }
            }
        }
        return abstractLogicFlowNodeBuilder;


    }

    /**
     * 获取下一个节点
     *
     * @param nodeModelMap
     * @param relationMap
     * @param oldNode
     * @return
     */
    private DesignerNodeModel getNextNode(Map<String, DesignerNodeModel> nodeModelMap, Map<String, List<String>> relationMap, DesignerNodeModel oldNode) {
        if ("end".equals(oldNode.getType())) {
            return null;
        }
        String id = oldNode.getId();
        List<String> ids = relationMap.get(id);
        if (Objects.isNull(ids)) {
            throw new LogicFlowException(StrUtil.format("解析错误，id = {} 获取下一节点失败", id));
        } else if (ids.size() == 1) {
            DesignerNodeModel nextNode = nodeModelMap.get(ids.get(0));
            if (Objects.isNull(nextNode)) {
                throw new LogicFlowException(StrUtil.format("解析错误，id = {} 获取下一节点失败", id));
            } else {
                return nextNode;
            }
        } else {
            throw new LogicFlowException(StrUtil.format("解析错误，id = {} 获取下一节点异常", id));
        }
    }

}
